package flexo.graphic;

import java.util.HashMap;

import flexo.file.*;
import flexo.math.Coords;

public class Font extends flexo.common.ReferenceCount
{
	class Glyph
	{
		float width;		
		int position;
	}
	
	protected HashMap<String,Glyph> glyphList;
	
	protected String name;
	protected String file;
	protected int numColumns;
	protected int numRows;
	protected float columnWidth;
	protected float rowHeight;
	protected int numChars;
	protected float widthAverage;
	
	/**
	 * Creates a new font.
	 * @param descriptionFile The xml file that describes the font
	 * @param textureName The texture with the font
	 */
	public Font(String file)
	{		
		this.file = file;
		glyphList = new HashMap<String, Glyph>();
		// First the descriptionFile is loaded
		flexo.file.FileSystem fs = (flexo.file.FileSystem)flexo.Kernel.getSystem(flexo.file.FileSystem.ID);
		File desc = fs.createFile(file);
		desc.load(new flexo.file.reader.Xml());
		
		Node font = desc.getRootNode().getChild("font");
		name = font.getProperty("name").getStringValue();
		
		flexo.Kernel.log("flexo.graphic.Font", "Creating font '"+name+"'");
		
		numColumns = font.getProperty("numColumns").getIntValue();
		numRows = font.getProperty("numRows").getIntValue();
		
		float texWidth = font.getProperty("texWidth").getFloatValue();
		columnWidth = font.getProperty("columnWidth").getIntValue();
		columnWidth = columnWidth/texWidth;
		
		rowHeight = font.getProperty("rowHeight").getIntValue();
		rowHeight = rowHeight/font.getProperty("texHeight").getFloatValue();
		
		numChars = font.getProperty("numChars").getIntValue();
		
		// Loading the glyph's info
		Node nGlyph;
		for (int i = 0; i < font.getChildrenCount(); ++i)
		{
			nGlyph = font.getChild(i);
			String character = nGlyph.getProperty("text").getStringValue();
			Glyph g = new Glyph();
			g.position = i;
			g.width = nGlyph.getProperty("width").getFloatValue() / texWidth;
			widthAverage += g.width;
			glyphList.put(character, g);
		}
		widthAverage /= font.getChildrenCount();
	}
	
	public float getAveragedAspectRatio()
	{
		return this.widthAverage / this.rowHeight;
	}
	
	public float getAspectRatio()
	{
		return this.columnWidth / this.rowHeight;
	}
	
	public void fillTexCoords(char c, Coords upperLeft, Coords lowerRight)
	{
		Glyph g = glyphList.get(String.valueOf(c));
		if (g != null)
		{
			int pos = g.position;
			
			int column = pos / numColumns;
			int row = pos % numColumns;
			
			upperLeft.x = (row * columnWidth) + (columnWidth/2.0f) - (g.width * 0.5f);
			upperLeft.y = column * rowHeight;		
					
			lowerRight.x = upperLeft.x + g.width;
			lowerRight.y = upperLeft.y + rowHeight;
		}
		else
		{
			upperLeft.x = 0;
			upperLeft.y = 0;
			lowerRight.x = 0;
			lowerRight.y = 0;
		}
	}
	
	public float getStringWidth(String s)
	{
		float width = 0;
		
		for (int i = 0; i < s.length(); ++i)
		{
			width += getCharWidth(s.charAt(i));
		}
		
		return width;
	}
	
	public float getCharWidth(char c)
	{
		if (c == ' ')
		{
			return (columnWidth / rowHeight) * 0.3f;
		}
		
		Glyph g = glyphList.get(String.valueOf(c));
		if (g == null)
		{
			return 0;
		}
		return g.width / rowHeight;
	}
	
	public String getName()
	{
		return name;
	}
	
	public String getDefaultMaterial()
	{
		// Text material
		GraphicSystem gs = (GraphicSystem)flexo.Kernel.getSystem(GraphicSystem.ID);
		Material mat = null;
		if (gs.existsMaterial(this.name))
		{
			mat = gs.getMaterial(this.name);
		}
		else
		{
			mat = gs.addMaterial(this.name,"default");
			mat.setBlending(flexo.graphic.Material.Blending.TRANSPARENT_ALPHA);
			String texFile = file.substring(0, file.length() - 4) + ".png";
			mat.getShaderParam("tex").setValue(texFile);
		}
		
		return this.name;
	}

	@Override
	protected void destroy()
	{
		flexo.graphic.GraphicSystem gs = (flexo.graphic.GraphicSystem)flexo.Kernel.getSystem(flexo.graphic.GraphicSystem.ID);
		gs.fontPool.remove(this);
	}
}
